using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using XRect = Microsoft.Xna.Framework.Rectangle;

// Use our tile editor
using xTile;
using xTile.Dimensions;
using xTile.Display;
using TRect = xTile.Dimensions.Rectangle;

using TiledPlatformer.Entity;

namespace TiledPlatformer
{
    /// <summary>
    /// This is the main class for your game.
    /// </summary>
    public class Platformer : Microsoft.Xna.Framework.Game
    {
        public static GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        // xTile-specific properties
        public static Map map;
        XnaDisplayDevice mapDisplayDevice;
        xTile.Dimensions.Rectangle viewport;

        public static Size viewportSize;
        SpriteFont arial;

        Player player;

        // A collection of rectangles which represent the collision rectangles of the terrain
        public static List<GameObject> gameObjects = new List<GameObject>(); 

        public Platformer()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        Ladder ladder;
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // Set the screen's width and height. If you change these, make sure you also change the size of your map
            int screen_width = 1680;
            int screen_height = 1050;

            ladder = new Ladder(new Vector2(200, 200), 4);
            gameObjects.Add(ladder);

            viewportSize = new Size(screen_width, screen_height);
            graphics.PreferredBackBufferWidth = viewportSize.Width;
            graphics.PreferredBackBufferHeight = viewportSize.Height;
            graphics.ApplyChanges();

            // Initialize xTile map display device
            mapDisplayDevice = new XnaDisplayDevice(
                this.Content, this.GraphicsDevice);

            //Initialize the xTile rendering viewport
            viewport = new xTile.Dimensions.Rectangle(viewportSize);

            // Create a dummy texture for drawing rectangles
            Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1, true, SurfaceFormat.Color);
            pixel.SetData(new[] {Color.White});

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            List<Map> mapList = new List<Map>();

            // Load the maps
            map = Content.Load<Map>("Maps\\default");

            // Load a font for debug text
            arial = Content.Load<SpriteFont>("arial");

            loadPlayer();

            // Initialize the xTile map's resources
            map.LoadTileSheets(mapDisplayDevice);

            mapList.Add(map);

            // Initialize a list containing rectangles formed from each rectangle on the collision layer
            xTile.Layers.Layer collisionLayer = map.GetLayer("collision");

            generateMap(mapList);

            // TODO: Load more of your game content here
        }

        private void generateMap(List<Map> mapList)
        {
            // Iterate through the collision layer and create a rectangle for each collision tile, adding it to the collection
            Location tile = new Location();
            foreach (Map m in mapList)
            {
                xTile.Layers.Layer l = m.GetLayer("collision");
                for (int i = 0; i < l.LayerWidth; ++i)
                {
                    for (int j = 0; j < l.LayerHeight; ++j)
                    {
                        tile.X = i;
                        tile.Y = j;

                        if (l.Tiles[tile] != null)
                        {
                            TRect tileRect = l.GetTileDisplayRectangle(viewport, tile);
                            gameObjects.Add(new GameObject(new Vector2(tileRect.X, tileRect.Y), tileRect.Width, tileRect.Height));
                        }
                    }
                }
            }
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                this.Exit();
            if (Keyboard.GetState().IsKeyDown(Keys.LeftControl))
                Initialize();

            // TODO: Add your update logic here
            //map.Update(gameTime.ElapsedGameTime.Milliseconds);

            player.Update();

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            map.Draw(mapDisplayDevice, viewport);


            spriteBatch.Begin();
            ladder.Draw(spriteBatch);
            player.Draw(spriteBatch);
            drawDebugText();
            spriteBatch.End();

            base.Draw(gameTime);
        }

        private void drawDebugText()
        {
            String positionText = String.Format("Position: [X: {0} Y: {1}]", player.position.X, Math.Round(player.position.Y));
            spriteBatch.DrawString(arial, positionText, new Vector2(20, 20), Color.Red, 0, Vector2.Zero, 0.7f, SpriteEffects.None, 0.5f);

            String positionText1 = String.Format("CantMove? Left: {0} | Right: {1}", player.cantMoveLeft, player.cantMoveRight);
            spriteBatch.DrawString(arial, positionText1, new Vector2(20, 40), Color.Red, 0, Vector2.Zero, 0.7f, SpriteEffects.None, 0.5f);

            String positionText2 = String.Format("Position: [X: {0} Y: {1}]", player.Velocity.X, Math.Round(player.Velocity.Y));
            spriteBatch.DrawString(arial, positionText2, new Vector2(20, 60), Color.Red, 0, Vector2.Zero, 0.7f, SpriteEffects.None, 0.5f); 
        }

        private void loadPlayer()
        {
            // Load the player's texture
            Texture2D playerTexture = Content.Load<Texture2D>("Images\\player");

            //Initialize a player
            player = new Player(new Vector2(200, 400), playerTexture, PlayerIndex.One);
        }
    }
}
